package com.d3works.apps.supplychain.service;

import com.d3works.apps.account.db.FiscalPosition;
import com.d3works.apps.account.db.TaxNumber;
import com.d3works.apps.account.service.config.AccountConfigService;
import com.d3works.apps.base.db.Company;
import com.d3works.apps.base.db.Currency;
import com.d3works.apps.base.db.Partner;
import com.d3works.apps.base.db.PriceList;
import com.d3works.apps.base.db.TradingName;
import com.d3works.apps.base.service.PartnerService;
import com.d3works.apps.base.service.app.AppBaseService;
import com.d3works.apps.sale.db.SaleOrder;
import com.d3works.apps.sale.db.repo.SaleOrderRepository;
import com.d3works.apps.sale.service.app.AppSaleService;
import com.d3works.apps.sale.service.saleorder.SaleOrderComputeService;
import com.d3works.apps.sale.service.saleorder.SaleOrderCreateServiceImpl;
import com.d3works.apps.sale.service.saleorder.SaleOrderService;
import com.d3works.apps.stock.db.Incoterm;
import com.d3works.apps.stock.db.StockLocation;
import com.d3works.apps.stock.service.StockLocationService;
import com.d3works.auth.AuthUtils;
import com.d3works.auth.db.User;
import com.d3works.exception.D3worksException;
import com.d3works.inject.Beans;
import com.d3works.team.db.Team;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.time.LocalDate;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SaleOrderCreateServiceSupplychainImpl extends SaleOrderCreateServiceImpl {

  private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

  protected AccountConfigService accountConfigService;
  protected SaleOrderRepository saleOrderRepository;
  protected AppBaseService appBaseService;

  @Inject
  public SaleOrderCreateServiceSupplychainImpl(
      PartnerService partnerService,
      SaleOrderRepository saleOrderRepo,
      AppSaleService appSaleService,
      AppBaseService appBaseService,
      SaleOrderService saleOrderService,
      SaleOrderComputeService saleOrderComputeService,
      AccountConfigService accountConfigService,
      SaleOrderRepository saleOrderRepository) {

    super(partnerService, saleOrderRepo, appSaleService, saleOrderService, saleOrderComputeService);

    this.accountConfigService = accountConfigService;
    this.saleOrderRepository = saleOrderRepository;
    this.appBaseService = appBaseService;
  }

  @Override
  public SaleOrder createSaleOrder(
      User salespersonUser,
      Company company,
      Partner contactPartner,
      Currency currency,
      LocalDate deliveryDate,
      String internalReference,
      String externalReference,
      PriceList priceList,
      Partner clientPartner,
      Team team,
      TaxNumber taxNumber,
      FiscalPosition fiscalPosition,
      TradingName tradingName)
      throws D3worksException {

    if (!appSaleService.isApp("supplychain")) {
      return super.createSaleOrder(
          salespersonUser,
          company,
          contactPartner,
          currency,
          deliveryDate,
          internalReference,
          externalReference,
          priceList,
          clientPartner,
          team,
          taxNumber,
          fiscalPosition,
          tradingName);
    }
    return createSaleOrder(
        salespersonUser,
        company,
        contactPartner,
        currency,
        deliveryDate,
        internalReference,
        externalReference,
        null,
        priceList,
        clientPartner,
        team,
        taxNumber,
        fiscalPosition,
        tradingName,
        null,
        null,
        null);
  }

  public SaleOrder createSaleOrder(
      User salespersonUser,
      Company company,
      Partner contactPartner,
      Currency currency,
      LocalDate deliveryDate,
      String internalReference,
      String externalReference,
      StockLocation stockLocation,
      PriceList priceList,
      Partner clientPartner,
      Team team,
      TaxNumber taxNumber,
      FiscalPosition fiscalPosition)
      throws D3worksException {

    return createSaleOrder(
        salespersonUser,
        company,
        contactPartner,
        currency,
        deliveryDate,
        internalReference,
        externalReference,
        stockLocation,
        priceList,
        clientPartner,
        team,
        taxNumber,
        fiscalPosition,
        null,
        null,
        null,
        null);
  }

  public SaleOrder createSaleOrder(
      User salespersonUser,
      Company company,
      Partner contactPartner,
      Currency currency,
      LocalDate deliveryDate,
      String internalReference,
      String externalReference,
      StockLocation stockLocation,
      PriceList priceList,
      Partner clientPartner,
      Team team,
      TaxNumber taxNumber,
      FiscalPosition fiscalPosition,
      TradingName tradingName,
      Incoterm incoterm,
      Partner invoicedPartner,
      Partner deliveredPartner)
      throws D3worksException {

    logger.debug(
        "Creation of a sale order : Company = {},  External reference = {}, Customer = {}",
        company.getName(),
        externalReference,
        clientPartner.getFullName());

    SaleOrder saleOrder =
        super.createSaleOrder(
            salespersonUser,
            company,
            contactPartner,
            currency,
            deliveryDate,
            internalReference,
            externalReference,
            priceList,
            clientPartner,
            team,
            taxNumber,
            fiscalPosition,
            tradingName);

    if (stockLocation == null) {
      stockLocation = Beans.get(StockLocationService.class).getPickupDefaultStockLocation(company);
    }

    saleOrder.setStockLocation(stockLocation);

    saleOrder.setPaymentMode(clientPartner.getInPaymentMode());
    saleOrder.setPaymentCondition(clientPartner.getPaymentCondition());
    saleOrder.setIncoterm(incoterm);
    saleOrder.setInvoicedPartner(invoicedPartner);
    saleOrder.setDeliveredPartner(deliveredPartner);

    if (saleOrder.getPaymentMode() == null) {
      saleOrder.setPaymentMode(
          this.accountConfigService.getAccountConfig(company).getInPaymentMode());
    }

    if (saleOrder.getPaymentCondition() == null) {
      saleOrder.setPaymentCondition(
          this.accountConfigService.getAccountConfig(company).getDefPaymentCondition());
    }

    saleOrder.setShipmentMode(clientPartner.getShipmentMode());
    saleOrder.setFreightCarrierMode(clientPartner.getFreightCarrierMode());

    return saleOrder;
  }

  @Transactional(rollbackOn = {Exception.class})
  public SaleOrder mergeSaleOrders(
      List<SaleOrder> saleOrderList,
      Currency currency,
      Partner clientPartner,
      Company company,
      StockLocation stockLocation,
      Partner contactPartner,
      PriceList priceList,
      Team team,
      TaxNumber taxNumber,
      FiscalPosition fiscalPosition,
      Incoterm incoterm,
      Partner invoicedPartner,
      Partner deliveredPartner)
      throws D3worksException {

    StringBuilder numSeq = new StringBuilder();
    StringBuilder externalRef = new StringBuilder();
    for (SaleOrder saleOrderLocal : saleOrderList) {
      if (numSeq.length() > 0) {
        numSeq.append("-");
      }
      numSeq.append(saleOrderLocal.getSaleOrderSeq());

      if (externalRef.length() > 0) {
        externalRef.append("|");
      }
      if (saleOrderLocal.getExternalReference() != null) {
        externalRef.append(saleOrderLocal.getExternalReference());
      }
    }

    SaleOrder saleOrderMerged =
        this.createSaleOrder(
            AuthUtils.getUser(),
            company,
            contactPartner,
            currency,
            null,
            numSeq.toString(),
            externalRef.toString(),
            stockLocation,
            priceList,
            clientPartner,
            team,
            taxNumber,
            fiscalPosition,
            null,
            incoterm,
            invoicedPartner,
            deliveredPartner);
    super.attachToNewSaleOrder(saleOrderList, saleOrderMerged);

    saleOrderComputeService.computeSaleOrder(saleOrderMerged);

    saleOrderRepository.save(saleOrderMerged);

    super.removeOldSaleOrders(saleOrderList);

    return saleOrderMerged;
  }
}
